<?php

require_once 'Pipes/FileSystem/ModelList/Finder.php';
require_once 'Pipes/FileSystem/ModelList/Loader.php';
require_once 'Pipes/FileSystem/ModelMeta/Finder.php';
require_once 'Pipes/FileSystem/ModelMeta/Loader.php';
require_once 'PipesImpl/Config.php';
require_once 'PipesImpl/Model/Relationship/Mapper.php';
require_once 'Pipes/Namespace/Parser.php';
require_once 'Pipes/Model/Mapper/Factory.php';

class Pipes_Model_Relationship_Mapper implements PipesImpl_Model_Relationship_Mapper
{
    private $_pdo = null;
    private $_config = null;
    private $_model = null;
    private $_listLoader = null;
    private $_metaLoader = null;
    
    public function __construct(PipesImpl_Config $config, PipesImpl_Model $model)
    {
        $this->_pdo = $config->pdo;
        $this->_config = $config;
        $this->_model = $model;

        $this->_listLoader = new Pipes_FileSystem_ModelList_Loader(
            new Pipes_FileSystem_ModelList_Finder($config)
        );

        $this->_metaLoader = new Pipes_FileSystem_ModelMeta_Loader(
            new Pipes_FileSystem_ModelMeta_Finder($config)
        );
    }
    
    public function getList($relationship)
    {
        // load Mapper - makes sure this really exists and also allows the 
        // mapper to do any initialization that is required
        $factory = new Pipes_Model_Mapper_Factory($this->_config);
        $mapper = $factory->factory($relationship);
        
        $modelName = $this->_model->getName() . 's';
        $modelId = $this->_model->idColumn()->name;
        $relationshipName = $relationship . 's';
        $relationshipId = $relationship . '_id';
        $sql = "
            SELECT 
                {$relationshipName}.*
            FROM 
                {$modelName}
                INNER JOIN {$modelName}_to_{$relationshipName} USING ({$modelId})
                INNER JOIN {$relationshipName} USING ({$relationshipId})
            WHERE
                {$modelName}.{$modelId} = ?";
        $statement = $this->_pdo->prepare($sql);
        $statement->execute(array($this->_model->$modelId));
        
        $recordSet = $statement->fetchAll(PDO::FETCH_ASSOC);
        $statement->closeCursor();
        
        $namespace = $this->_config->namespace;
        $name = ucfirst($relationship);
        
        $this->_listLoader->load($name);
        $modelListName = $this->_listLoader->lastLoaded;

        $this->_metaLoader->load($name);
        $metaName = $this->_metaLoader->lastLoaded;
        $meta = new $metaName($this->_config);
        
        $modelList = new $modelListName($this->_config, $meta, $recordSet);
        $modelList->attachSave(array($this, 'save'));
        $modelList->attachRemove(array($this, 'remove'));
        return  $modelList;
    }
    
    public function save(PipesImpl_Model $model)
    {
        $isNew = $model->isNew();
        $factory = new Pipes_Model_Mapper_Factory($this->_config);
        $mapper = $factory->factory($model->getName());
        
        $mapper->save($model);
        
        $modelName = $this->_model->getName() . 's';
        $modelId = $this->_model->idColumn()->name;
        $relationshipName = $model->getName() . 's';
        $relationshipId = $model->idColumn()->name;

        if ($isNew) {
            $sql = "
                INSERT INTO 
                    {$modelName}_to_{$relationshipName}
                VALUES
                    (:{$modelId}, :{$relationshipId})";
            $statement = $this->_pdo->prepare($sql);
            
            $params = array(
                ":{$modelId}" => $this->_model->$modelId,
                ":{$relationshipId}" => $model->$relationshipId
            );
            $statement->execute($params);
        } else {
            $sql = "REPLACE INTO
                        {$modelName}_to_{$relationshipName}
                    VALUES
                        (:{$modelId}, :{$relationshipId})";
            $statement = $this->_pdo->prepare($sql);
            $params = array(
                ":{$modelId}" => $this->_model->$modelId,
                ":{$relationshipId}" => $model->$relationshipId
            );
            
            $statement->execute($params);
        }
    }

    public function remove(PipesImpl_Model $model) {
        $modelId = $this->_model->idColumn()->name;
        $relationshipId = $model->idColumn()->name;
        $sql = "
            DELETE FROM 
                {$this->_model->getName()}s_to_{$model->getName()}s
            WHERE
                {$modelId} = ?
                AND {$relationshipId} = ?
            LIMIT 1";

        $statement = $this->_pdo->prepare($sql);
        $statement->execute(
            array(
                $this->_model->$modelId,
                $model->$relationshipId
            )
        );
    }
}
